package com.chenfan.ccp.plug.hot;

import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;

public class ClassHotStart {

	private static String classPath;
	private static String staticPath;
	private static String targetStaticPath;
	private static String RESOURCES = "resources";


	static {
		URL resource = Thread.currentThread().
			getContextClassLoader().
			getResource("");
		if (resource != null) {
			File currentFile = new File(resource.getPath());
			classPath = currentFile.getPath();
			staticPath = getCurrentDicPath();
			targetStaticPath = currentFile.getParent() + File.separator + RESOURCES;

		}


	}

	/**
	 * 寻找main方法
	 *
	 * @return
	 */
	private static Class<?> findMainApplicationClass() {
		try {
			StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
			for (StackTraceElement stackTraceElement : stackTrace) {
				if ("main".equals(stackTraceElement.getMethodName())) {
					return Class.forName(stackTraceElement.getClassName());
				}
			}
		} catch (ClassNotFoundException ex) {
		}
		return null;
	}

	private static String getCurrentDicPath() {
		//当前目录上一级就是运行的类
		String className = findMainApplicationClass().getSimpleName();

		if (className.isEmpty()) {
			return "";
		}

		String currentExecClassName = className.split("\\$")[0].replaceAll("\\.",
			File.separator.equalsIgnoreCase("\\") ? "\\\\" : File.separator) + ".java";
		String absoluteFiles = getAbsoluteFiles(currentExecClassName, Paths.get(".").toFile());
		String javaDicHome = absoluteFiles.substring(0, absoluteFiles.lastIndexOf(currentExecClassName));
		String resourcesDic = javaDicHome.substring(0, javaDicHome.lastIndexOf("java")) + "resources";

		return resourcesDic;
	}

	/**
	 * 根据路径获取对应的文件的绝对路径
	 *
	 * @param fileName 文件的地址
	 * @param pathFile 文件的根目录
	 * @return
	 */
	private static String getAbsoluteFiles(String fileName, File pathFile) {
		File[] files = pathFile.listFiles();
		String resultPath = "";
		for (File file : files) {
			if (!resultPath.isEmpty()) {
				break;
			}
			if (file.isDirectory()) {
				resultPath = getAbsoluteFiles(fileName, file);
			} else if (file.getName().endsWith(".java") && file.getAbsolutePath().endsWith(fileName)) {
				resultPath = file.getAbsolutePath();
				break;
			}
		}

		return resultPath;

	}


	public static void start(Class classz, String... args) {
		new ClassFileChange(
			arg -> {
				try {
					String filePath = (String) arg;


					//更新静态文件和类
					if (filePath.startsWith(classPath)) {

						String canonicalName = filePath.substring(classPath.length() + 1).replaceAll("//|/|\\\\", ".");

						Class<?> aClass = ClassHotLoader.getInstance().loadClass(
							canonicalName.substring(0, canonicalName.lastIndexOf(".")));

						if (aClass != null && isSpringAnnotation(aClass.getAnnotations()) && ClassHotLoader.isOk()) {
							synchronized (ClassHotStart.class) {
								//启动类
								ClassHotLoader.getInstance().start(classz, args);
							}
						}

					} else if (filePath.startsWith(staticPath)) {
						synchronized (ClassHotStart.class) {

							//拷贝静态资源
							copyFile(filePath, targetStaticPath +
								filePath.substring(filePath.indexOf(RESOURCES) + RESOURCES.length()));

						}


					}
				} catch (Exception e) {
					e.printStackTrace();
				}

				return null;
			}, classPath, staticPath).start();

		ClassHotLoader.getInstance().start(classz, args);
	}


	/**
	 * 判断是否是spring的注解,用来判断是否需要重启服务
	 *
	 * @param annotations
	 */
	private static boolean isSpringAnnotation(Annotation[] annotations) {
		for (Annotation annotation : annotations) {
			if (!annotation.annotationType().getCanonicalName().startsWith("org.springframework")) {
				continue;
			}

			if (annotation.annotationType().getDeclaredAnnotation(Component.class) != null) {
				return true;

			} else {


				return isSpringAnnotation(annotation.annotationType().getDeclaredAnnotations());
			}

		}
		return false;
	}

	/**
	 * 复制文件
	 *
	 * @param sourcePath 来源的路径
	 * @param destPath   目标的路径
	 */
	private static void copyFile(String sourcePath, String destPath) {

		File sourceFile = new File(sourcePath);
		if (!sourceFile.exists() || sourceFile.isDirectory()) {
			return;
		}


		File destFile = new File(destPath);


		if (!destFile.exists()) {
			destFile.getParentFile().mkdirs();
		}


		FileChannel inputChannel = null;
		FileChannel outputChannel = null;
		try {
			inputChannel = new FileInputStream(sourceFile).getChannel();
			outputChannel = new FileOutputStream(destFile).getChannel();
			outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
		} catch (Exception e) {

		} finally {
			try {
				inputChannel.close();
			} catch (IOException e) {

			}
			try {
				outputChannel.close();
			} catch (IOException e) {

			}
		}

	}


}
